home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2010 April / PCWorld0410.iso / redakcyjne / programy / VideoLAN Client (VLC) 1.0.5 / vlc-1.0.5-win32.exe / lua / intf / http.lua < prev    next >
Text File  |  2010-01-30  |  9KB  |  287 lines

  1. --[==========================================================================[
  2.  http.lua: HTTP interface module for VLC
  3. --[==========================================================================[
  4.  Copyright (C) 2007 the VideoLAN team
  5.  $Id$
  6.  
  7.  Authors: Antoine Cellerier <dionoea at videolan dot org>
  8.  
  9.  This program is free software; you can redistribute it and/or modify
  10.  it under the terms of the GNU General Public License as published by
  11.  the Free Software Foundation; either version 2 of the License, or
  12.  (at your option) any later version.
  13.  
  14.  This program is distributed in the hope that it will be useful,
  15.  but WITHOUT ANY WARRANTY; without even the implied warranty of
  16.  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17.  GNU General Public License for more details.
  18.  
  19.  You should have received a copy of the GNU General Public License
  20.  along with this program; if not, write to the Free Software
  21.  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  22. --]==========================================================================]
  23.  
  24. --[==========================================================================[
  25. Configuration options:
  26.  * host: A host to listen on.
  27.  * dir: Directory to use as the http interface's root.
  28.  * no_error_detail: If set, do not print the Lua error message when generating
  29.                     a page fails.
  30.  * no_index: If set, don't build directory indexes
  31. --]==========================================================================]
  32.  
  33.  
  34. require "common"
  35.  
  36. vlc.msg.info("Lua HTTP interface")
  37.  
  38. open_tag = "<?vlc"
  39. close_tag = "?>"
  40.  
  41. function escape(s)
  42.     return (string.gsub(s,"([%^%$%%%.%[%]%*%+%-%?])","%%%1"))
  43. end
  44.  
  45. function process_raw(filename)
  46.     local input = io.open(filename):read("*a")
  47.     -- find the longest [===[ or ]=====] type sequence and make sure that
  48.     -- we use one that's longer.
  49.     local str="X"
  50.     for str2 in string.gmatch(input,"[%[%]]=*[%[%]]") do
  51.         if #str < #str2 then str = str2 end
  52.     end
  53.     str=string.rep("=",#str-1)
  54.  
  55.     --[[┬áFIXME:
  56.     <?xml version="1.0" encoding="charset" standalone="yes" ?> is still a problem. The closing '?>' needs to be printed using '?<?vlc print ">" ?>' to prevent a parse error.
  57.     --]]
  58.     local code0 = string.gsub(input,escape(close_tag)," print(["..str.."[")
  59.     local code1 = string.gsub(code0,escape(open_tag),"]"..str.."]) ")
  60.     local code = "print(["..str.."["..code1.."]"..str.."])"
  61.     --[[ Uncomment to debug
  62.     if string.match(filename,"vlm_cmd.xml$") then
  63.     io.write(code)
  64.     io.write("\n")
  65.     end
  66.     --]]
  67.     return assert(loadstring(code,filename))
  68. end
  69. function process(filename)
  70.     local mtime = 0    -- vlc.net.stat(filename).modification_time
  71.     local func = false -- process_raw(filename)
  72.     return function(...)
  73.         local new_mtime = vlc.net.stat(filename).modification_time
  74.         if new_mtime ~= mtime then
  75.             -- Re-read the file if it changed
  76.             if mtime == 0 then
  77.                 vlc.msg.dbg("Loading `"..filename.."'")
  78.             else
  79.                 vlc.msg.dbg("Reloading `"..filename.."'")
  80.             end
  81.             func = process_raw(filename)
  82.             mtime = new_mtime
  83.         end
  84.         return func(...)
  85.     end
  86. end
  87.  
  88.  
  89. function callback_error(path,url,msg)
  90.     local url = url or "<page unknown>"
  91.     return  [[<html xmlns="http://www.w3.org/1999/xhtml">
  92. <head>
  93. <title>Error loading ]]..url..[[</title>
  94. </head>
  95. <body>
  96. <h1>Error loading ]]..url..[[</h1><pre>]]..(config.no_error_detail and "Remove configuration option `no_error_detail' on the server to get more information." or tostring(msg))..[[</pre>
  97. <p>
  98. <a href="http://www.videolan.org/">VideoLAN</a><br/>
  99. <a href="http://www.lua.org/manual/5.1/">Lua 5.1 Reference Manual</a>
  100. </p>
  101. </body>
  102. </html>]]
  103. end
  104.  
  105. function dirlisting(url,listing,acl_)
  106.     local list = {}
  107.     for _,f in ipairs(listing) do
  108.         if not string.match(f,"^%.") then
  109.             table.insert(list,"<li><a href='"..f.."'>"..f.."</a></li>")
  110.         end
  111.     end
  112.     list = table.concat(list)
  113.     local function callback()
  114.         return [[<html xmlns="http://www.w3.org/1999/xhtml">
  115. <head>
  116. <title>Directory listing ]]..url..[[</title>
  117. </head>
  118. <body>
  119. <h1>Directory listing ]]..url..[[</h1><ul>]]..list..[[</ul>
  120. </body>
  121. </html>]]
  122.     end
  123.     return h:file(url,"text/html",nil,nil,acl_,callback,nil)
  124. end
  125.  
  126. function file(h,path,url,acl_,mime)
  127.     local generate_page = process(path)
  128.     local callback = function(data,request)
  129.         -- FIXME: I'm sure that we could define a real sandbox
  130.         -- redefine print
  131.         local page = {}
  132.         local function pageprint(...)
  133.             for i=1,select("#",...) do
  134.                 if i== 1 then
  135.                     table.insert(page,tostring(select(i,...)))
  136.                 else
  137.                     table.insert(page," "..tostring(select(i,...)))
  138.                 end
  139.             end
  140.         end
  141.         _G._GET = parse_url_request(request)
  142.         local oldprint = print
  143.         print = pageprint
  144.         local ok, msg = pcall(generate_page)
  145.         -- reset
  146.         print = oldprint
  147.         if not ok then
  148.             return callback_error(path,url,msg)
  149.         end
  150.         return table.concat(page)
  151.     end
  152.     return h:file(url or path,mime,nil,nil,acl_,callback,nil)
  153. end
  154.  
  155. function rawfile(h,path,url,acl_)
  156.     local filename = path
  157.     local mtime = 0    -- vlc.net.stat(filename).modification_time
  158.     local page = false -- io.open(filename):read("*a")
  159.     local callback = function(data,request)
  160.         local new_mtime = vlc.net.stat(filename).modification_time
  161.         if mtime ~= new_mtime then
  162.             -- Re-read the file if it changed
  163.             if mtime == 0 then
  164.                 vlc.msg.dbg("Loading `"..filename.."'")
  165.             else
  166.                 vlc.msg.dbg("Reloading `"..filename.."'")
  167.             end
  168.             page = io.open(filename):read("*a")
  169.             mtime = new_mtime
  170.         end
  171.         return page
  172.     end
  173.     return h:file(url or path,nil,nil,nil,acl_,callback,nil)
  174. end
  175.  
  176. function parse_url_request(request)
  177.     if not request then return {} end
  178.     t = {}
  179.     for k,v in string.gmatch(request,"([^=&]+)=?([^=&]*)") do
  180.         local k_ = vlc.strings.decode_uri(k)
  181.         local v_ = vlc.strings.decode_uri(v)
  182.         if t[k_] ~= nil then
  183.             local t2
  184.             if type(t[k_]) ~= "table" then
  185.                 t2 = {}
  186.                 table.insert(t2,t[k_])
  187.                 t[k_] = t2
  188.             else
  189.                 t2 = t[k_]
  190.             end
  191.             table.insert(t2,v_)
  192.         else
  193.             t[k_] = v_
  194.         end
  195.     end
  196.     return t
  197. end
  198.  
  199. local function find_datadir(name)
  200.     local list = vlc.misc.datadir_list(name)
  201.     for _, l in ipairs(list) do
  202.         local s = vlc.net.stat(l)
  203.         if s then
  204.             return l
  205.         end
  206.     end
  207.     error("Unable to find the `"..name.."' directory.")
  208. end
  209. http_dir = config.dir or find_datadir("http")
  210.  
  211. do
  212.     local oldpath = package.path
  213.     package.path = http_dir.."/?.lua"
  214.     local ok, err = pcall(require,"custom")
  215.     if not ok then
  216.         vlc.msg.warn("Couldn't load "..http_dir.."/custom.lua")
  217.     else
  218.         vlc.msg.dbg("Loaded "..http_dir.."/custom.lua")
  219.     end
  220.     package.path = oldpath
  221. end
  222. local files = {}
  223. local mimes = {
  224.     txt = "text/plain",
  225.     html = "text/html",
  226.     xml = "text/xml",
  227.     js = "text/javascript",
  228.     css = "text/css",
  229.     png = "image/png",
  230.     ico = "image/x-icon",
  231. }
  232. local function load_dir(dir,root,parent_acl)
  233.     local root = root or "/"
  234.     local has_index = false
  235.     local my_acl = parent_acl
  236.     do
  237.         local af = dir.."/.hosts"
  238.         local s = vlc.net.stat(af)
  239.         if s and s.type == "file" then
  240.             -- We found an acl
  241.             my_acl = vlc.acl(false)
  242.             my_acl:load_file(af)
  243.         end
  244.     end
  245.     local d = vlc.net.opendir(dir)
  246.     for _,f in ipairs(d) do
  247.         if not string.match(f,"^%.") then
  248.             local s = vlc.net.stat(dir.."/"..f)
  249.             if s.type == "file" then
  250.                 local url
  251.                 if f == "index.html" then
  252.                     url = root
  253.                     has_index = true
  254.                 else
  255.                     url = root..f
  256.                 end
  257.                 local ext = string.match(f,"%.([^%.]-)$")
  258.                 local mime = mimes[ext]
  259.                 -- print(url,mime)
  260.                 if mime and string.match(mime,"^text/") then
  261.                     table.insert(files,file(h,dir.."/"..f,url,my_acl and my_acl.private,mime))
  262.                 else
  263.                     table.insert(files,rawfile(h,dir.."/"..f,url,my_acl and my_acl.private))
  264.                 end
  265.             elseif s.type == "dir" then
  266.                 load_dir(dir.."/"..f,root..f.."/",my_acl)
  267.             end
  268.         end
  269.     end
  270.     if not has_index and not config.no_index then
  271.         -- print("Adding index for", root)
  272.         table.insert(files,dirlisting(root,d,my_acl and my_acl.private))
  273.     end
  274. end
  275.  
  276. local u = vlc.net.url_parse( config.host or "localhost:8080" )
  277. h = vlc.httpd(u.host,u.port)
  278. load_dir( http_dir )
  279.  
  280. while not vlc.misc.lock_and_wait() do end -- everything happens in callbacks
  281.  
  282. -- FIXME: We shouldn't need to do this ourselves.
  283. for i=1,#files do
  284.     getmetatable(files[i]).__gc(files[i])
  285.     files[i] = nil
  286. end
  287.